// futures 官方文档： https://docs.rs/futures/0.3.30/futures/index.html
// https://course.rs/advance/async/future-excuting.html
/*
Rust 的 futures 库是用于编写异步代码的一个核心库。它提供了一组基础类型和实用工具，可以帮助开发者编写非阻塞的、异步的 Rust 程序。
futures 库是 Rust 异步编程模型的核心部分之一，它与 async/await 特性紧密集成，使得编写并发代码变得更加简单和直观。
futures 库的主要特性
    Future 类型: futures 定义了 Future trait，它是所有异步计算的基础。一个实现了 Future trait 的类型代表了一个异步计算，它可以被等待完成或者被组合成更复杂的异步计算。
    Async/await 语法: Rust 的 async/await 语法与 futures 库紧密相关，使异步代码看起来类似于同步代码。
    实用的 Future 组合器: futures 提供了许多实用的组合器，如 select, then, map, filter 等，这些组合器可以用来组合不同的 Future 实例。
    流(Streams): futures 还支持流(Stream)，这是一种可以产生一系列值的异步计算。
    任务(Task) 管理: 用于控制和管理异步任务的执行。
*/
use futures::channel::mpsc;
use futures::executor;
use futures::executor::{ThreadPool, ThreadPoolBuilder};

fn main() {
    // 该类型仅在激活该库的 thread-pool 线程池功能时可用。
    let pool = ThreadPool::new().expect("Failed to build pool");
    // 创建默认线程池配置。有关默认配置的详细信息，请参阅该类型的其他方法。
    let thread_pool = ThreadPoolBuilder::new()
        // 设置未来线程池的大小，线程池的大小是指生成的工作线程数。默认情况下，它等于 CPU 内核数。
        .pool_size(4)
        // 设置未来 ThreadPool 的线程名称前缀。默认情况下，工作线程分配的是 Rust 的标准线程名。
        .name_prefix("my-pool-")
        // 使用给定的配置创建 ThreadPool。
        .create()
        .expect("TODO: panic message");


    // 效果等同于上面代码
    // 默认情况下，默认配置只设置了线程池的大小。要设置其他配置，请使用 ThreadPoolBuilder::default() 方法。并在其后调用其相关方法。
    let pool = ThreadPoolBuilder::default()
        .name_prefix("my-pool-")
        .create()
        .expect("Failed to build pool");


    let (tx, rx) = mpsc::unbounded::<i32>();

    // Create a future by an async block, where async is responsible for an
    // implementation of Future. At this point no executor has been provided
    // to this future, so it will not be running.
    let fut_values = async {
        // Create another async block, again where the Future implementation
        // is generated by async. Since this is inside of a parent async block,
        // it will be provided with the executor of the parent block when the parent
        // block is executed.
        //
        // This executor chaining is done by Future::poll whose second argument
        // is a std::task::Context. This represents our executor, and the Future
        // implemented by this async block can be polled using the parent async
        // block's executor.
        let fut_tx_result = async move {
            (0..100).for_each(|v| {
                tx.unbounded_send(v).expect("Failed to send");
            })
        };

        // Use the provided thread pool to spawn the generated future
        // responsible for transmission
        pool.spawn_ok(fut_tx_result);

        let fut_values = rx
            .map(|v| v * 2)
            .collect();

        // Use the executor provided to this async block to wait for the
        // future to complete.
        fut_values.await
    };

    // Actually execute the above future, which will invoke Future::poll and
    // subsequently chain appropriate Future::poll and methods needing executors
    // to drive all futures. Eventually fut_values will be driven to completion.
    let values: Vec<i32> = executor::block_on(fut_values);

    println!("Values={:?}", values);
}